package br.unicamp.integralization.tests;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import br.unicamp.integralization.bab.BranchAndBound;
import br.unicamp.integralization.dto.Allocation;
import br.unicamp.integralization.dto.History;
import br.unicamp.integralization.request.RequestDTO;
import br.unicamp.integralization.request.RequestStatusEnum;
import br.unicamp.integralization.request.ValidationConstants;
import br.unicamp.integralization.request.ValidationHelper;

import com.google.gson.Gson;


public class Bab {

	public static void main(String[] args) {
		String ra = "691067";
		History hist = null;
		String requestURL = "http://www.students.ic.unicamp.br/~ra104864/mc857/servidorDac/rest/obter_dados.php"
				+ "?ra=" + ra;
		try {
			System.out.println(requestURL);
			InputStream input = new URL(requestURL).openStream();
			Reader reader = new InputStreamReader(input, "UTF-8");

			hist = (History) new Gson().fromJson(reader, History.class);
		} catch (IOException e1) {
			e1.printStackTrace();
		}

		try {
//			 Thread.sleep(20000);
			//System.out.println(hist);
			System.out.println("Start");
			long nano = System.nanoTime();
			Allocation bestAllocation = BranchAndBound.execute(hist);
//			 Allocation diff = BranchAndBound.diff(hist.getAllocation(),
//					bestAllocation);
			//System.out.println(hist);
			System.out.println("Tempo para processar :"
					+ (System.nanoTime() - nano)/1000000 + " ms");
			//System.out.println("Best:");
			//System.out.println(bestAllocation);

			bestAllocation.getElectiveGroups().remove(
					bestAllocation.getElectiveGroups().size() - 1);
			String params = "ra=" + ra + "&alocacao="
					+ new Gson().toJson(bestAllocation);

			RequestDTO result;
			try {
				result = downloadUrl(requestURL, "POST", params);
			} catch (Exception e) {
				result = new RequestDTO(
						RequestStatusEnum.CONNECTION_ERROR.code(), null, null);
			}

			if (result.getStatus() == RequestStatusEnum.OK.code()) {
				System.out.println("OK =D");
			} else {
				System.out.println("D:");
			}
//			 System.out.println("Diff");
//			 System.out.println(diff);

		} catch (Exception e) {
			System.err.println("Isso jamais deveria ter acontecido D:");
			e.printStackTrace();
		}

	}

	public static RequestDTO downloadUrl(String myurl, String method,
			String params) throws IOException {
		InputStream is = null;
/*		 Only display the first 5000 characters of the retrieved
		 web page content.*/
		try {
//			 define method
			method = ValidationHelper.isEmptyOrVoid(method) ? "GET" : method;

//			 variables
			URL url;

			url = new URL(myurl);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setReadTimeout(20000); //milliseconds
			conn.setConnectTimeout(40000); //milliseconds
			conn.setRequestMethod(method);
			conn.setDoInput(true);

//			 write post params
			if (method.equals("POST")) {

				conn.setRequestProperty("Accept-Charset", "UTF-8");
				conn.setRequestProperty("Content-Type",
						"application/x-www-form-urlencoded;charset=UTF-8");
				conn.setDoOutput(true);
				OutputStream output = null;
				try {
					output = conn.getOutputStream();
					output.write(params.getBytes("UTF-8"));
				} finally {
					if (output != null)
						try {
							output.close();
						} catch (IOException logOrIgnore) {
						}
				}

			}

//			 Starts the query
			conn.connect();
			int response = conn.getResponseCode();
			String contentAsString = "";

			if (HttpURLConnection.HTTP_OK == response) {
				try {

					is = conn.getInputStream();

//					 Convert the InputStream into a string
					contentAsString = readIt(is);

//					 try to read as a string, if valid return success
					if (ValidationHelper.isValid(contentAsString,
							ValidationConstants.NUMBER)) {
						return new RequestDTO(RequestStatusEnum.OK.code(),
								contentAsString, null);
					}

//					 try to read the success json
					JSONObject jObject = new JSONObject(contentAsString);
					try {
						Boolean ret = jObject.getBoolean("success");

						if (ret != null && !ret) {
							return new RequestDTO(
									RequestStatusEnum.ERROR.code(), jObject
											.getJSONObject("error").getString(
													"msg"), jObject
											.getJSONObject("error").getString(
													"code"));
						} else {
							return new RequestDTO(RequestStatusEnum.OK.code(),
									contentAsString, null);
						}
					} catch (JSONException e) {
//						 if couldn't read success attribute return OK because
//						 contentAsString is a JSONObject
						return new RequestDTO(RequestStatusEnum.OK.code(),
								contentAsString, null);
					}

				} catch (JSONException e) {

					try {
//						 try to read the success json as an array
						new JSONArray(contentAsString);

//						 if couldn't read success attribute return OK because
//						 contentAsString is a JSONObject
						return new RequestDTO(RequestStatusEnum.OK.code(),
								contentAsString, null);
					} catch (JSONException exception) {
//						 json isn't in the expected format
						return new RequestDTO(RequestStatusEnum.ERROR.code(),
								contentAsString, null);
					} catch (Exception exception) {
						return new RequestDTO(
								RequestStatusEnum.CONNECTION_ERROR.code(),
								contentAsString, null);
					}

				} catch (Exception e) {
					return new RequestDTO(
							RequestStatusEnum.CONNECTION_ERROR.code(),
							contentAsString, null);
				}
			} else if (HttpURLConnection.HTTP_INTERNAL_ERROR == response) {
				try {
					is = conn.getErrorStream();

//					 Convert the InputStream into a string
					contentAsString = readIt(is);

//					 try to read the error json
					JSONObject jObject = new JSONObject(contentAsString);
					return new RequestDTO(RequestStatusEnum.ERROR.code(),
							jObject.getJSONObject("error").getString("msg"),
							jObject.getJSONObject("error").getString("code"));
				} catch (Exception e) {
					return new RequestDTO(
							RequestStatusEnum.CONNECTION_ERROR.code(), null,
							null);
				}
			} else {

				return new RequestDTO(
						RequestStatusEnum.CONNECTION_ERROR.code(), null, null);
			}

		} catch (Exception e) {
			return new RequestDTO(RequestStatusEnum.CONNECTION_ERROR.code(),
					null, null);
		} finally {

//			 Makes sure that the InputStream is closed after the app is
//			 finished using it.
			if (is != null) {
				is.close();
			}
		}
	}

	public static String readIt(InputStream stream) throws IOException,
			UnsupportedEncodingException {

//		 read it with BufferedReader
		BufferedReader br = new BufferedReader(new InputStreamReader(stream));

		StringBuilder sb = new StringBuilder();

		String line;
		while ((line = br.readLine()) != null) {
			sb.append(line);
		}

		return sb.toString();
	}

}
